/*
* $Id: unet_main.c,v 1.73 2008/03/10 05:31:10 sunny Exp $
*/
/*******************************************************************************

       UBEC (Uniband Electronic Corp.)

       Project: U-NET01, Ubiquitous network platform

       File: main.c

       Version: 0.3.0

       Usage: Sample Code

       Platform: U-NET01 DK with Keil 8051 C compiler

       Reference:

               Silicon Laboratories: C8051F124, C8051F340

               UBEC: UZ2400, UZ2410

       Note :

               Copyright (C) 2007 Uniband Electronic Corporation, All rights reserved

********************************************************************************/

//#if defined(__K0__)
//#pragma section @@DATA @@UNMAIN
//#pragma inline  // enable memcpy() and memset() with direct inline expansion instead of function call
//#endif // #if __K0__

#include "unet.h"

/*******************************************************************************
********************************************************************************/
void SystemInit( void );

UINT8 MAC_ADDRESS[8] = {My_MAC_Address0, My_MAC_Address1, My_MAC_Address2, My_MAC_Address3,
			My_MAC_Address4, My_MAC_Address5, My_MAC_Address6, My_MAC_Address7};

//char DATA_BUFF[100];

#ifdef CHECKSUM
UINT16 RunIndex = 0;
#endif

/*******************************************************************************
********************************************************************************/
void main()
{
//	UINT8 DATA_LENGTH;
#ifndef TIMER_1MS
	struct _child_list_ *ChiPtr;
#endif

	DisInt();
        SystemInit( );
	EnabInt();          // enable interrupt in main() when everything is ready

#if 0
	while(1) {
		putchar('U');	// DEBUG only: for UART baud rate measurement
	}
#endif

	Link_LED_On();
	RxTx_LED_On();
	UART_LED_On();
	User_LED_On();

	init_unet_vars();
	srand(GetMacAddress());

	AppInit();	// init. user application

	Link_LED_Off();
	RxTx_LED_Off();
	UART_LED_Off();
	User_LED_Off();


#ifdef I_Am_Coordinator
	UNET_GET_INFOMATION();
	UNET_GET_TABLE();
#endif // #ifdef I_Am_Coordinator

#ifdef CHECKSUM
	ReceivedNumber = 0;
#endif

	while(1){
		if(!UnetSys.Flag.NwkReady) {	// Network reset
		#ifdef I_Am_Coordinator
			if(UNET_ESTABLISH() == SUCCESS) {
				UNET_GET_INFOMATION();
				UNET_GET_TABLE();

				chdalive_tm = setup_timer(3000, 0, UnetChildAliveCheck, NULL);
				gettable_tm = setup_timer(1000, 0, UNET_GET_TABLE, NULL);

			}
			else {
			}
		#else
			if(UNET_JOIN() == SUCCESS) {
				chdalive_tm = setup_timer(3000, 0, UnetChildAliveCheck, NULL);
				reqtable_tm = setup_timer(10000, 0, (void (*)())RxUnetReqTable, NULL);

#if UNET_POLL_INTERVAL != 0
				poll_tm = setup_timer(UNET_POLL_INTERVAL, 0, (void (*)())TxUnetLocalTalk, NULL);
				poll.flag.up_poll_flg = 1;
				User_LED_On();
#endif
			}
			else {
			}
		#endif // #ifdef I_Am_Coordinator
		}
		else {
			//Check the queue whether the data incoming
			if(CHECK_UNET_DATA()){
				UINT8 Length;
				void *MsgPtr = RECV_FROM_UNET(&Length);

				if(MsgPtr) {	// TODO: process the received user packet
					if(!AppProcUnetRxData((UNET_HEADER *)MsgPtr, Length))
						RxUnetData((UNET_HEADER *)MsgPtr, Length);
					free(MsgPtr);
				}
			}

			if(UnetSys.Flag.NwkReset){
				NetworkReset();
				//UNET_INIT(UnetSys.JoinPID, UnetSys.Channel, UnetSys.RejoinParent);
			}

			//Process the tx failure situation
			if(UnetSys.Flag.TxFailure){
				TRACE_puts("TX_FAILURE");
				UnetRecovery(tx_failure_address);
				UnetSys.Flag.TxFailure = 0;
				UnetSys.Flag.PermitJoin = 1;
			}

#ifndef TIMER_1MS
			//The child poll its parent
			if(poll.flag.up_poll_flg){
				poll.up_poll_counter+=1;
				if(poll.up_poll_counter == poll.ETA){
					TxUnetLocalTalk();
					poll.up_poll_counter = 0;
				}
			}

			//The parent check whether its child alive
			if(poll.flag.down_poll_flg){
				poll.down_poll_counter+=1;
				if(poll.down_poll_counter == (poll.ETA+poll.ETA)){
					TRACE_puts("POLL_TIME_UP");
					if((ChiPtr = UnetSys.ChildTail) != NULL) {
					    do{
							ChiPtr = ChiPtr->Next;
							if(ChiPtr->rx_polling_switch){
								TRACE_printf(("address: %04X, ", ChiPtr->NetworkAddress));
									if(ChiPtr->rx_polling_flg)
										ChiPtr->rx_polling_flg = 0;
									else{
										ChiPtr->rx_polling_switch = 0;
										TxUnetLocalTalkAlert(ChiPtr->NetworkAddress);
										if(UnetSys.Flag.TxFailure){
											UnetRecovery(tx_failure_address);
											UnetSys.Flag.TxFailure = 0;
											UnetSys.Flag.PermitJoin = 1;
											break;
										}

									}
							}
						}while(ChiPtr != UnetSys.ChildTail);
					}
					poll.down_poll_counter = 0;
				} // down_poll_counter
			}//down_poll_flg
#endif

		#ifdef CHECKSUM
			RunIndex+=1;
			if(UnetSys.Flag.JoinNetwork && RunIndex == 0x1000){
				UINT8 Data[50];
				UINT8 i;
				for(i=0;i<50;i++)
					Data[i] = i;

				UNET_TX16(UNET_COORD_ADDRESS, Data, 50);

				RunIndex = 0x0;
			}
		#endif // #ifdef CHECKSUM
		} // if(!UnetSys.Flag.NwkReady)

		if(timer_1ms_flag) {
			update_timer_chain();
		}

	#ifdef CONSOLE
		ProcUartRxData();

		//Process the UART command
		if(UART_BUFF.FLAG) {
		#ifdef I_Am_Coordinator
			UINT16 KickChildAddr, NewParentAddr;
			UINT32 PollingInterval;
		#endif  // #ifdef I_Am_Coordinator
			UINT16 DstNwkAddr;
			UINT8 DataLength;

		#if defined(I_Am_Coordinator) && DEBUG_FUNC
			UINT16 command_interval;
			UINT8  execute;
		#endif

			// 2007/7/4 17:10, Sunny: fix the endian problem on NEC platform
			DstNwkAddr = (UINT16)((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[0]) << 8;
			DstNwkAddr |= (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[1];

			switch((*(UARTDATA *)UART_BUFF.UNET_CMD).Command){
				case UNET_DATA:
					DataLength = (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[2];
					#ifdef I_Am_Coordinator
					if(UnetTxCheck(DstNwkAddr))
					#endif
						UNET_TX16(DstNwkAddr, &(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[3], DataLength);
					break;
				case UNET_LEAVE_CMD:
					if(!UnetSys.Flag.PanCoordinator)
						UNET_LEAVE();
					break;
				case UNET_ASK_MAC_ADDR:
					if(!UnetSys.Flag.PanCoordinator)
						UNET_ADDR16_64(DstNwkAddr);
					break;
				case UNET_PERMIT_JOIN:
					if((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[0] == 0)
						UnetSys.Flag.PermitJoin = 0;
					else
						UnetSys.Flag.PermitJoin = 1;
					break;
				case UNET_MAC_ROUTE:
					if(!UnetSys.Flag.PanCoordinator){
						DataLength = (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[8];
						UNET_TX64(&(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[0],
						  &(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[9], DataLength);
					}
					break;

				case UNET_GET_INFO:
					UNET_GET_INFOMATION();
					break;

			#ifdef I_Am_Coordinator
				case UNET_RESET:
					if(UnetTxCheck(DstNwkAddr))
						UNET_REMOTE_RESET(DstNwkAddr, (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[2], (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[3], (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[4]);
					break;
				case UNET_KICK_CMD:
					KickChildAddr = (UINT16)((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[2]) << 8;
					KickChildAddr |= (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[3];
					NewParentAddr = (UINT16)((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[4]) << 8;
					NewParentAddr |= (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[5];

					//if(UnetTxCheck(DstNwkAddr))
						UNET_KICK(DstNwkAddr /* ParentNWKAddr */, KickChildAddr, NewParentAddr);
					break;
				case UNET_REQ_ROUTERTAB:
					UNET_GET_TABLE();
					break;

				case UNET_QUERY_CMD:
					if(UnetTxCheck(DstNwkAddr))
						UNET_QUERY(DstNwkAddr);
					break;
				case UNET_LOCAL_QUERY:
					PollingInterval = (UINT32)(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[2] << 24;
					PollingInterval |= (UINT32)(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[3] << 16;
					PollingInterval |= (UINT32)(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[4] << 8;
					PollingInterval |= (UINT32)(*(UARTDATA *)UART_BUFF.UNET_CMD).Data[5];
					if(UnetTxCheck(DstNwkAddr))
						TxUnetLocalQuery(DstNwkAddr, PollingInterval, (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[6]);
					break;
				case UNET_REQ_TAB:
					if(UnetTxCheck(DstNwkAddr))
						TxUnetReqTable(DstNwkAddr);
					break;
			#if DEBUG_FUNC
				case UNET_DBG_RSSI_QUERY:
					execute = (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[0];
					command_interval = (UINT16)((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[1]) << 8;
					command_interval |= (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[2];
					if(execute == 0x1)
						rssi_dbg_tm = setup_timer(((UINT32)command_interval), 0, dbg_rssi_query, NULL);
					else
						close_timer(rssi_dbg_tm);
					break;
				case UNET_DBG_NODE_INFO_REQ:
					if(UnetTxCheck(DstNwkAddr))
						dbg_tx_node_info_req(DstNwkAddr);
					break;
				case UNET_DBG_CHILD_MONITOR:
					dbg_child_number_set((*(UARTDATA *)UART_BUFF.UNET_CMD).Data[0], (*(UARTDATA *)UART_BUFF.UNET_CMD).Data[1]);
					break;
			#endif // #ifdef DEBUG_FUNC

			#endif // #ifdef I_Am_Coordinator

				default:
					if(!AppProcUartRxData(UART_BUFF.UNET_CMD, UART_BUFF.LENGTH)) {
						puts("\rUnknown UART command: 0x");
						print_hex((*(UARTDATA *)UART_BUFF.UNET_CMD).Command);
						puts(", Length: ");
						print_uint(UART_BUFF.LENGTH);
					}
					break;
			}

		// 2007/8/7 12:27, Sunny: Removed for UART I/O via interrupt driven.
		//	DisInt();
		//	memset(&UART_BUFF, 0, sizeof(UART_INTERFACE));
		//	EnabInt();

			UART_BUFF.FLAG = 0;
		} // if(UART_BUFF.FLAG)
	#endif // #ifdef CONSOLE

		//call user application
		AppMain();
	}

}
